package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"sync"
 "flag"
	"github.com/zserge/lorca"
	"os/exec"
	"io"
	"strings"
// "time"

	"github.com/rakyll/statik/fs"
	_ "app/statik"

)

var (
	SOURCE_DIR string
)

type counter struct {
	sync.Mutex
	count int
}

func (c *counter) Add(n int) {
	c.Lock()
	defer c.Unlock()
	c.count = c.count + n
}

func (c *counter) Value() int {
	c.Lock()
	defer c.Unlock()
	return c.count
}

//通过管道同步获取日志的函数
func syncLog(is_dev bool,logger *log.Logger, reader io.ReadCloser) {
	
	//因为logger的print方法会自动添加一个换行，所以我们需要一个cache暂存不满一行的log
	cache := ""
	buf := make([]byte, 1024, 1024)
	for {
		strNum, err := reader.Read(buf)
		if strNum > 0 {
			outputByte := buf[:strNum]
			//这里的切分是为了将整行的log提取出来，然后将不满整行和下次一同打印
			outputSlice := strings.Split(string(outputByte), "\n")
			logText := strings.Join(outputSlice[:len(outputSlice)-1], "\n")
			logger.Printf("%s%s", cache, logText)


			fmt.Printf("%s%s\n", cache, logText)
		
			if find := strings.Contains(logText, "Note that the development build is not optimized.")||strings.Contains(logText, "Done"); find {
				if is_dev==true{
				
	args := getArgs()
				
	// Create UI with basic HTML passed via data URI
	ui, err := lorca.New("", "", 480, 320, args...)
	if err != nil {
		log.Fatal(err)
	}
	defer ui.Close()

	c := &counter{}
	ui.Bind("counterAdd", c.Add)
	ui.Bind("counterValue", c.Value)


						fmt.Println("find the character.")
				
					ui.Load(fmt.Sprintf("http://%s", "127.0.0.1:8080"))
					GoProgram(ui)
				}else{
					fmt.Println("find the character.")
					}
					
			}
	

			cache = outputSlice[len(outputSlice)-1]
		}
		if err != nil {
			if err == io.EOF || strings.Contains(err.Error(), "file already closed") {
				err = nil
			}
		}
	}
}
// 判断目录是否存在
func IsDir(fileAddr string)bool{
	s,err:=os.Stat(fileAddr)
	if err!=nil{
		log.Println(err)
		return false
	}
	return s.IsDir()
}

func main() {

	//获取是否开发环境参数
    is_dev:=false
    flag.BoolVar(&is_dev, "dev", false, "是否开发模式")
    //这里有一个非常重要的操作,转换， 必须调用该方法
    flag.Parse()

	
	cmdStr :=""
	//如果是开发模式则直接使用命令运行vue 否则运行打包后的vue
	if is_dev!= false {

	cmdStr = "cd ./vue && yarn serve"

	cmd := exec.Command("bash", "-c", cmdStr)
	//这里得到标准输出和标准错误输出的两个管道，此处获取了错误处理
	cmdStdoutPipe, _ := cmd.StdoutPipe()
	cmdStderrPipe, _ := cmd.StderrPipe()
	
	err:= cmd.Start()
	
	if err != nil {
		fmt.Println(err)
	}
	//打开一个文件，用作log封装输出
	f, _ := os.OpenFile("file.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	defer f.Close()
	//创建封装的log，第三个参数设置log输出的格式
	logger := log.New(f, "", log.LstdFlags)
	logger.Print("start print log:")
	oldFlags := logger.Flags()
	//为了保证shell的输出和标准的log格式不冲突，并且为了整齐，关闭logger自身的格式
	logger.SetFlags(0)

	go syncLog(is_dev,logger, cmdStdoutPipe)
	go syncLog(is_dev,logger, cmdStderrPipe)
	err = cmd.Wait()
	//执行完后再打开log输出的格式
	logger.SetFlags(oldFlags)
	logger.Print("log print done")
	if err != nil {
		fmt.Println(err)
	}
	}
	// else{
	// 	cmdStr = "rm -rf  ./statik/  &&cd ./vue && yarn build&& cd ../"
	// }


//非开发模式直接跑起来即可
	if is_dev!=true{

		args := getArgs()
				
		// Create UI with basic HTML passed via data URI
		ui, err := lorca.New("", "", 480, 320, args...)
		if err != nil {
			log.Fatal(err)
		}
		defer ui.Close()
	
		c := &counter{}
		ui.Bind("counterAdd", c.Add)
		ui.Bind("counterValue", c.Value)

				// statik -src=./vue/dist/ -f

				// statik_cmd := exec.Command("bash", "-c", "statik -src=./vue/dist/ -f")
				
				// sta_err:= statik_cmd.Start()
				
				// if sta_err != nil {
				// 	fmt.Println(sta_err)
				// }
				// err = statik_cmd.Wait()
				// if err != nil {
				// 	fmt.Println(err)
				// }

				// isDirStatik:=false
				// isDirStatik=IsDir("./statik")
				// for isDirStatik!=true {
				// 	isDirStatik=IsDir("./statik")
				// }

				// time.Sleep(2e9)

				statikFS, err := fs.New()
				if err != nil {
				  log.Fatal(err)
				}
				ln, err := net.Listen("tcp", "127.0.0.1:8800")
				if err != nil {
					log.Fatal(err)
				}
			
			defer ln.Close()
			go http.Serve(ln, http.FileServer(statikFS))
			ui.Load(fmt.Sprintf("http://%s", ln.Addr()))


				GoProgram(ui)
	}



	// Wait until the interrupt signal arrives or browser window is closed
// 	sigc := make(chan os.Signal)
// 	signal.Notify(sigc, os.Interrupt)
// 	select {
// 	case <-sigc:
// 	case <-ui.Done():
// 	}
// 	log.Println("exiting...")
}
func GoProgram (ui lorca.UI){
	// Wait until the interrupt signal arrives or browser window is closed
	sigc := make(chan os.Signal)
	signal.Notify(sigc, os.Interrupt)
	select {
	case <-sigc:
	case <-ui.Done():
	}
	log.Println("exiting...")
}
// getArgs
func getArgs() (args []string) {
	if runtime.GOOS == "linux" {
		args = append(args, "--class=Lorca")
	}
	return args
}

func getHtmlDir() string {
	if SOURCE_DIR == "" {
		return "./vue/dist"
	}
	return SOURCE_DIR
}
